<?php


namespace app\openapi\controller;


use app\common\validate\RequestCheckValidate;
use think\App;
use think\facade\Request;
use think\Loader;

class OpenApi
{
    /**
     * redis key
     * @Author zengxin(573908667@qq.com)
     * @var mixed|string
     */
    protected $redis_key;

    /**
     * @var Request Request 实例
     */
    protected $request;

    /**
     * 无需登录的方法,同时也就不需要鉴权了
     * @var array
     */
    protected $noNeedLogin = [];

    /**
     * 当前第几页
     * Author zengxin(573908667@qq.com)
     * @var int
     */
    protected $page = 1;

    /**
     * 每页显示数量
     * Author zengxin(573908667@qq.com)
     * @var int
     */
    protected $page_size = 10;

    /**
     * 当前请求路径
     */
    protected $current_path;

    /**
     * @var array 前置操作方法列表
     */
    protected $beforeActionList = [];

    /**
     * OpenApi constructor.
     * @param Request|null $request
     */
    public function __construct(Request $request = null)
    {
        $this->request = is_null($request) ? Request::instance() : $request;

        // 计算项目名称
        $temp            = explode("/", str_replace('\\', '/', substr(app()->getRootPath(), 0, strlen(app()->getRootPath()) - 1)));
        $this->redis_key = end($temp);

        $this->_init();

        // 前置操作方法
        if ($this->beforeActionList) {
            foreach ($this->beforeActionList as $method => $options) {
                is_numeric($method) ?
                    $this->beforeAction($options) :
                    $this->beforeAction($method, $options);
            }
        }
    }

    /**
     * 前置操作
     * @access protected
     * @param string $method 前置操作方法名
     * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]]
     * @return void
     */
    protected function beforeAction($method, $options = [])
    {
        if (isset($options['only'])) {
            if (is_string($options['only'])) {
                $options['only'] = explode(',', $options['only']);
            }

            if (!in_array($this->request->action(), $options['only'])) {
                return;
            }
        } elseif (isset($options['except'])) {
            if (is_string($options['except'])) {
                $options['except'] = explode(',', $options['except']);
            }

            if (in_array($this->request->action(), $options['except'])) {
                return;
            }
        }

        call_user_func([$this, $method]);
    }

    /**
     * 初始化
     * @Author zengxin(573908667@qq.com)
     */
    private function _init()
    {
        //跨域请求检测
        check_cors_request();

        $controller_name = Loader::parseName(Request::controller());
        $action_name     = strtolower(Request::action());

        $content_type = Request::header('content-type');
        if(strpos($content_type,'application/json') === false) err_return('content-type格式不正确');

        $this->current_path = str_replace('.', '/', $controller_name) . '/' . $action_name;

        $this->page      = input('page', 1);
        $this->page_size = input('page_size', 10);

        if (!$this->match($this->noNeedLogin)) {
            $token = Request::header('token');
            if (empty($token)) err_return('token invalid');

            $redis    = redis_instance();
            $is_cache = $redis->exists("{$this->redis_key}:openapi:{$token}");

            if (!$is_cache) err_return('token invalid');

            //校验参数是否合法
            checkParam(new RequestCheckValidate(),'check');
        }
    }

    /**
     * 检测当前控制器和方法是否匹配传递的数组
     * @param array $arr 需要验证权限的数组
     * @return boolean
     */
    protected function match($arr = [])
    {
        $request = Request::instance();
        $arr     = is_array($arr) ? $arr : explode(',', $arr);
        if (!$arr) {
            return false;
        }
        $arr = array_map('strtolower', $arr);
        // 是否存在
        if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) {
            return true;
        }

        // 没找到匹配
        return false;
    }

}